package com.apes.framework.plugin.workflow;

import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Connector;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.workflow.lib.WorkflowApi;
import com.apes.framework.query.SqlService;
import com.apes.framework.rop.session.SimpleSession;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.service.PostService;
import com.apestech.api.workflow.WorkFlow;
import com.apestech.api.workflow.lib.element.FlowTask;
import com.apestech.api.workflow.lib.element.WorkProcessEngine;
import com.apestech.api.workflow.xml.ExtendNode;
import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.util.FileUtil;
import com.apestech.framework.util.LocalVariable;
import com.apestech.framework.util.StringUtil;
import org.flowable.engine.ProcessEngine;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 工作流服务
 *
 * @author hup
 * @create 2018-07-23-13:58
 */
@Service("workFlowService")
public class WorkFlowService {

    @Autowired
    private ProcessEngine engine;

    @Qualifier("workflowApi")
    @Autowired
    private WorkflowApi workapi;
    @Autowired
    SqlService sqlService;

    /**
     * 功能：执行任务
     */
    public Map executeTask(SimpleRequest request) {
        Map variables = writeSessionData(request);
        String taskId = request.get("wfTaskId");
        variables.putAll(getExtendJSON(new JSONObject(variables)));
        workapi.executeTask(taskId, variables);
        return new HashMap();
    }

    /**
     * 会签发起
     *
     * @param param
     * @throws Exception
     */
    public Map counterSign(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            WorkFlow workFlow = new WorkFlow(engine);
            input = workFlow.startCounterSign(input);
            String login = input.getString("loginUserName");
            String to = input.getString("counterUserName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[会签发起]" + to + ":\r\n" + memo);
            workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 加签
     *
     * @param param
     * @throws Exception
     */
    public Map addSign(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            String login = input.getString("loginUserName");
            String to = input.getString("userName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[加签]" + to + ":\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            String statu = workFlow.getNodeState(input);
            if ("addSign".equals(statu)) {
                workFlow.addSign(input);
            } else {
                workFlow.startAddSign(input);
            }
            workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 转签
     *
     * @param param
     * @throws Exception
     */
    public Map changeSign(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            changeSignInner(input, false);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private void changeSignInner(JSONObject input, Boolean innerChangeSignFlag){
        try {
            String login = input.getString("loginUserName");
            String to = input.getString("userName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[转签]" + to + ":\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            String statu = workFlow.getNodeState(input);
            if ("addSign".equals(statu)) {
                workFlow.changeAddSign(input);
            } else {
                workFlow.changeSignTask(input);
            }
            workapi.sendExtendMsg(input, innerChangeSignFlag);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 委托开始
     *
     * @param param
     * @throws Exception
     */
    public Map startCommission(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            String login = input.getString("loginUserName");
            String to = input.getString("userName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[委托]" + to + ":\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.startCommission(input);
            workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 委托中止
     *
     * @param param
     * @throws Exception
     */
    public Map stopCommission(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            String login = input.getString("loginUserName");
            input.put("wf_comments", login + "[委托中止]");
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.stopCommission(login);
            workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 中止流程：行政审批流可用，流程编排不允许使用！！！
     *
     * @param param
     */
    public Map stopProcess(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            String login = input.getString("loginUserName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[中止]:\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            workapi.sendStopMsg(workFlow.stopProcess(input), input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 驳回，传入任务ID为当前运行任务ID
     *
     * @param param
     * @return
     */
    public Map refoulement(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            String login = input.getString("loginUserName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[驳回]:\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.refoulement(input);
            //workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 撤回，传任务ID，为当前正在执行的流程实例下已经完成的任务ID，待办消息传入要调整
     *
     * @param param
     * @return
     */
    public Map rollBack(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            if (input.get("wf_comments") == null) {
                input.put("wf_comments", "");
            }
            String login = input.getString("loginUserName");
            String memo = input.getString("wf_comments");
            input.put("wf_comments", login + "[撤回]:\r\n" + memo);
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.rollBack(input);
            //workapi.sendExtendMsg(input);
            return new HashMap();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void getProcessInstancePng(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            WorkFlow workFlow = new WorkFlow(engine);
            InputStream imageStream = workFlow.getProcessInstancePng(input);
            HttpServletResponse response = (HttpServletResponse) param.getRopRequestContext().getRawResponseObject();
            response.addHeader("Access-Control-Allow-Origin", "*");
            //response.setContentType("application/octet-stream;charset=utf-8");
            response.setContentType("image/png;charset=utf-8");
            byte[] bytes = new byte[1024];
            int length;
            while ((length = imageStream.read(bytes, 0, 1024)) != -1) {
                response.getOutputStream().write(bytes, 0, length);
            }
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 根据人员ID查询待办
     *
     * @param param
     * @throws Exception
     */
    public void getUserToDoTask(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            String userId = input.getString("userId");
            if (userId == null) {
                throw new RuntimeException("待办查询人员ID不允许为空！");
            }
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.getUserToDoTask(userId);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    /**
     * 开启流程，测试专用，真实场景不用！！！
     *
     * @param param
     */
    public String startProcess(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            WorkFlow workFlow = new WorkFlow(engine);
            return workFlow.startProcess(input).toString();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void updateDeployment(SimpleRequest param) {
        JSONObject input = null;
        try {
            input = getExtendJSON(new JSONObject(writeSessionData(param)));
            String dir = input.getString("dir");
            if (dir == null) {
                dir = LocalVariable.getWorkflowDir();
            }
            deployment(dir);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void deployment(String fileAbsolutePath) {
        try {
            if (!FileUtil.isFileExist(fileAbsolutePath)) {
                throw new RuntimeException("请输入合法目录！");
            }
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.refreshDeployment(fileAbsolutePath);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void iniDataBase(SimpleRequest param) {
        try {
            WorkFlow workFlow = new WorkFlow(engine);
            workFlow.iniDataBase();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void writeExtendWorkFlow(SimpleRequest param) throws RuntimeException {
        try {
            String body = (String) param.getData();
            JSONObject json = JSON.toJSON(body);
            String key = json.getString("key");
            String filename = json.getString("filename");
            ExtendNode node = new ExtendNode(key);
            if (filename != null) {
                node.setFileName(filename);
            }
            node.write();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private void wirteInnerChangeSign(JSONObject param){
        try {
            JSONObject input=new JSONObject();
            input.put("taskId", param.getString("taskId"));
            FlowTask flowTask=new FlowTask(new WorkProcessEngine(engine), input);
            if(flowTask.getTask()==null){
                throw new Exception("当前任务结点不存在，请检查！");
            }
            flowTask.getExecNode();
            Task task= flowTask.getTask();
            if(task.getAssignee()!=null){
                input.put("loginUserId", task.getAssignee());
                input.put("loginUserName", param.getString("loginUserName"));
                input.put("userId", param.getString("loginUserId"));
                input.put("userName", param.getString("loginUserName"));
                input.put("wf_comments","内部转签");
                input.put("taskExecutor", task.getAssignee());
                changeSignInner(input, true);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    private Map writeSessionData(SimpleRequest request) {
        Map variables = request.getMap();
        SimpleSession session = (SimpleSession) request.getRopRequestContext().getSession();
        if (session != null) {
            String taskExecutor = session.getUserId(); //任务执行人
            variables.put("taskExecutor", taskExecutor);
            variables.put("taskExecutorName", session.getUserName());
            PostService postService = SpringManager.getBean(PostService.class);
            Post post = postService.findOne(session.getPostId());
            if (post.getBranch() != null) variables.put("taskExecutorDepartment", post.getBranch().getId()); //任务执行部门
            if (post.getWorkPost() != null) variables.put("taskExecutorPost", post.getWorkPost().getId()); //任务执行岗位
        }
        return variables;
    }

    private JSONObject getExtendJSON(JSONObject input) {
        if (input == null) return null;
        input.put("taskId", input.get("wfTaskId"));
        input.put("opinion", input.get("wf_comments"));
        Object user = input.get("wf_user");
        if (user != null) {
            if (user instanceof Map) {
                input.put("userId", ((Map) user).get("id"));
                input.put("userName", ((Map) user).get("name"));
            } else {
                JSONArray userlist = new JSONArray();
                int len = ((List) user).size();
                for (int i = 0; i < len; i++) {
                    Map m = (Map) ((List) user).get(i);
                    userlist.add(addUser(StringUtil.castToString(m.get("id")), StringUtil.castToString(m.get("name"))));
                }
                input.put("userlist", userlist);
            }
        }
        if (input.get("taskExecutor") != null) {
            input.put("loginUserId", input.get("taskExecutor"));
            input.put("loginUserName", input.get("taskExecutorName"));
        }
        if(input.get("changeSignFlag")!=null && (Boolean) input.get("changeSignFlag"))
           wirteInnerChangeSign(input);
        return input;
    }

    private JSONObject addUser(String id, String name) {
        JSONObject map = new JSONObject();
        map.put("userId", id);
        map.put("userName", name);
        return map;
    }

    public JSONArray getProcName(SimpleRequest request) {
        String sSQL = "SELECT T.NAME_ NAME, T.KEY_ ID FROM  ACT_RE_PROCDEF T WHERE 1 = 1  GROUP BY T.NAME_ , T.KEY_";
        return sqlService.query(sSQL);
    }

    /**
     * 指定执行某个任务
     * @param map 表单数据
     * @param taskId 任务ID
     * @param wf_state 1 || 0
     * @param taskExecutor 任务执行人 为空默认使用超级管理员
     */
    public void assignTaskExecute(Map map,String taskId,int wf_state,String taskExecutor){
        map.put("wfTaskId",taskId);
        map.put("wf_comments","超72小时未确认系统自动确认");
        map.put("wf_variable_wf_state",wf_state);
        map.put("taskExecutor",taskExecutor == null ? "1" : taskExecutor);
        map.putAll(getExtendJSON(new JSONObject(map)));
    }

}
